/*************************************************elog_cfg.h*************************************************/
#ifndef __ELOG_H__
#define __ELOG_H__

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "configure.h"



#ifdef __cplusplus
extern "C" {
#endif

/* enable log output. default open this macro */
#define ELOG_OUTPUT_ENABLE
/* setting static output log level */
#define ELOG_OUTPUT_LVL                      ELOG_LVL_VERBOSE
/* enable assert check */
#define ELOG_ASSERT_ENABLE
/* log buffer size */
#define ELOG_BUF_SIZE                        2048
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN                5
/* output filter's tag max length */
#define ELOG_FILTER_TAG_MAX_LEN              16
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN               16
/* output level string max length */
#define ELOG_LEVEL_NAME_MAX_LEN               16
/* output newline sign */
#define ELOG_NEWLINE_SIGN                    "\n"

#define ELOG_CONFIGURE_SHM_KEY               0x3478
#define ELOG_CONFIGURE_FILE_PATH             "/usrdata/loglevel.conf"


#if !defined(ELOG_OUTPUT_LVL)
#error "Please configure static output log level (in elog_cfg.h)"
#endif

#if !defined(ELOG_LINE_NUM_MAX_LEN)
#error "Please configure output line number max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_BUF_SIZE)
#error "Please configure log buffer size (in elog_cfg.h)"
#endif

#if !defined(ELOG_FILTER_TAG_MAX_LEN)
#error "Please configure output filter's tag max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_FILTER_KW_MAX_LEN)
#error "Please configure output filter's keyword max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_NEWLINE_SIGN)
#error "Please configure output newline sign (in elog_cfg.h)"
#endif

#define DEBUG	1
#define DBG_ALL	1
#define LY_INFO(...)

/* output log's level */
#define ELOG_LVL_ASSERT                      0
#define ELOG_LVL_ERROR                       1
#define ELOG_LVL_WARN                        2
#define ELOG_LVL_INFO                        3
#define ELOG_LVL_DEBUG                       4
#define ELOG_LVL_VERBOSE                     5

/* output log's level total number */
#define ELOG_LVL_TOTAL_NUM                   6

/* EasyLogger software version number */
#define ELOG_SW_VERSION                      "1.05.13"

#define D_LOG_BUFF_ALL_MAX					10240//10K
/* EasyLogger assert for developer. */
#ifdef ELOG_ASSERT_ENABLE
#define ELOG_ASSERT(EXPR)                                                     \
if (!(EXPR))                                                                  \
{                                                                             \
    if (elog_assert_hook == NULL) {                                           \
        elog_a("elog", "(%s) has assert failed at %s:%ld.", #EXPR, __FUNCTION__, __LINE__); \
        while (1);                                                            \
    } else {                                                                  \
        elog_assert_hook(#EXPR, __FUNCTION__, __LINE__);                      \
    }                                                                         \
}
#else
#define ELOG_ASSERT(EXPR)                    ((void)0);
#endif

/* all formats index */
typedef enum
{
    ELOG_FMT_LVL    = 1 << 0, /**< level */
    ELOG_FMT_TAG    = 1 << 1, /**< tag */
    ELOG_FMT_TIME   = 1 << 2, /**< current time */
    ELOG_FMT_P_INFO = 1 << 3, /**< process info */
    ELOG_FMT_T_INFO = 1 << 4, /**< thread info */
    ELOG_FMT_DIR    = 1 << 5, /**< file directory and name */
    ELOG_FMT_FUNC   = 1 << 6, /**< function name */
    ELOG_FMT_LINE   = 1 << 7, /**< line number */
} ElogFmtIndex;

/* macro definition for all formats */
#define ELOG_FMT_ALL    (ELOG_FMT_LVL|ELOG_FMT_TAG|ELOG_FMT_TIME| \
    ELOG_FMT_DIR|ELOG_FMT_FUNC|ELOG_FMT_LINE)//|ELOG_FMT_P_INFO|ELOG_FMT_T_INFO

/* output log's filter */
typedef struct
{
    uint8_t level;
    char tag[ELOG_FILTER_TAG_MAX_LEN + 1];
    char keyword[ELOG_FILTER_KW_MAX_LEN + 1];
} ElogFilter, *ElogFilter_t;


typedef struct 
{
	char Make_PCall				:1;
	char Make_Sms				:1;
	char Make_AnswerCall		:1;

	char PHY_Error				:1;
	char F_unused				:4; 
	
}_CTL_MODE;

typedef union{
	char ctl_mode_byte;
	_CTL_MODE m_ctl_mode;
}SYS_CTL_MODE;


typedef struct
{
	SYS_CTL_MODE sys_ctl;
	char xCallStatus;
} ElogCtlShare, *ElogCtlShare_t;


/* easy logger */
typedef struct
{
    ElogFilter filter;
    size_t enabled_fmt_set[ELOG_LVL_TOTAL_NUM];
    bool output_enabled;
	
	pthread_mutex_t sharedLock;
	unsigned int  log_len;
	unsigned int  log_len_Save;
	ElogCtlShare sys_ctl_share;
	char log_buf_Print[D_LOG_BUFF_ALL_MAX];
	char log_buf_Save[D_LOG_BUFF_ALL_MAX];
} EasyLogger, *EasyLogger_t;

/* EasyLogger error code */
typedef enum
{
    ELOG_NO_ERR,
} ElogErrCode;

typedef struct {
	void (*pfSysLogWriteFile)(const char *log, size_t size); 
}User_FuncSet;

/* elog.c */
ElogErrCode elog_init(void);
void elog_start(void);
void elog_set_output_enabled(bool enabled);
bool elog_get_output_enabled(void);
void elog_set_fmt(uint8_t level, size_t set);
void elog_set_filter(uint8_t level, const char *tag, const char *keyword);
void elog_set_filter_lvl(uint8_t level);
void elog_get_filter_lvl(uint8_t* level);

void elog_set_filter_tag(const char *tag);
void elog_get_filter_tag( char *tag);

void elog_set_filter_kw(const char *keyword);
void elog_get_filter_kw( char *keyword);

void elog_raw(const char *format, ...);
void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
                 const long line, const char *format, ...);
void elog_output_lock_enabled(bool enabled);
extern void (*elog_assert_hook)(const char* expr, const char* func, size_t line);
void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line));

#ifndef ELOG_OUTPUT_ENABLE

#define elog_a(tag, ...)
#define elog_e(tag, ...)
#define elog_w(tag, ...)
#define elog_i(tag, ...)
#define elog_d(tag, ...)
#define elog_v(tag, ...)

#else /* ELOG_OUTPUT_ENABLE */

#if ELOG_OUTPUT_LVL >= ELOG_LVL_ASSERT
#define elog_assert(tag, ...) \
        elog_output(ELOG_LVL_ASSERT, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_assert(tag, ...)
#endif

#if ELOG_OUTPUT_LVL >= ELOG_LVL_ERROR
#define elog_error(tag, ...) \
        elog_output(ELOG_LVL_ERROR, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_error(tag, ...)
#endif

#if ELOG_OUTPUT_LVL >= ELOG_LVL_WARN
#define elog_warn(tag, ...) \
        elog_output(ELOG_LVL_WARN, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_warn(tag, ...)
#endif

#if ELOG_OUTPUT_LVL >= ELOG_LVL_INFO
#define elog_info(tag, ...) \
        elog_output(ELOG_LVL_INFO, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_info(tag, ...)
#endif

#if ELOG_OUTPUT_LVL >= ELOG_LVL_DEBUG
#define elog_debug(tag, ...) \
        elog_output(ELOG_LVL_DEBUG, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_debug(tag, ...)
#endif

#if ELOG_OUTPUT_LVL == ELOG_LVL_VERBOSE
#define elog_verbose(tag, ...) \
        elog_output(ELOG_LVL_VERBOSE, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_verbose(tag, ...)
#endif

#endif /* ELOG_OUTPUT_ENABLE */

#define elog_rw(...) \
        elog_raw(__VA_ARGS__)

#define elog_a(tag, ...)    elog_assert(tag, __VA_ARGS__)
#define elog_e(tag, ...)    elog_error(tag, __VA_ARGS__)
#define elog_w(tag, ...)    elog_warn(tag, __VA_ARGS__)
#define elog_i(tag, ...)    elog_info(tag, __VA_ARGS__)
#define elog_d(tag, ...)    elog_debug(tag, __VA_ARGS__)
#define elog_v(tag, ...)    elog_verbose(tag, __VA_ARGS__)


size_t elog_strcpy(size_t cur_len, char *dst, const char *src);
ElogErrCode elog_port_init(void);
void elog_port_output(uint8_t level,const char *log, size_t size);
void elog_port_output_lock(void);
void elog_port_output_unlock(void);
const char *elog_port_get_time(void);
const char *elog_port_get_p_info(void);
const char *elog_port_get_t_info(void);


extern void * Get_LogConfigure_ShareMemory(size_t size, int *shmid);
extern void Save_LogLevel_Configure(uint8_t level);
extern uint8_t  Get_LogLevel_Configure();
extern void Delete_Configure_ShareMemory(void *shm, int shmid);
extern void  Quit_ShareMemory();
extern void elog_port_PrintData();
extern void Elog_Master_Init();
extern void Elog_UserFunc_Set(User_FuncSet* pfUser);

extern void Sys_CtlSet(SYS_CTL_MODE* ctl_mode ,bool beSet);
extern void Sys_xCallStatusSet(char * xCallStatus ,bool beSet);
extern int do_system_call(const char *fmt, ...);

FILE * gettcufd();

#ifndef LOGV
#ifdef DEBUG
#define LOGV(LOG_TAG, ...) do {\
        ((void)elog_verbose(LOG_TAG, __VA_ARGS__)); \
    }while(0)
#else
#define LOGV(LOG_TAG, fmt, arg...) (printf( __VA_ARGS__)) //LY_INFO("[%s]"fmt,LOG_TAG, ##arg)
#endif
#endif

#ifndef LOGD
#ifdef DEBUG
#define LOGD(LOG_TAG, ...) do {\
        ((void)elog_debug(LOG_TAG, __VA_ARGS__)); \
    }while(0)
#else
#define LOGD(LOG_TAG, fmt, arg...) (printf( __VA_ARGS__))// LY_INFO("[%s]"fmt,LOG_TAG, ##arg)
#endif
#endif

#ifndef LOGI
#ifdef DEBUG
#define LOGI(LOG_TAG, ...) do {\
        ((void)elog_info(LOG_TAG, __VA_ARGS__));    \
    }while(0)
#else
#define LOGI(LOG_TAG, fmt, arg...) (printf( __VA_ARGS__))// LY_INFO("[%s]"fmt,LOG_TAG, ##arg)
#endif
#endif

#ifndef LOGW
#ifdef DEBUG
#define LOGW(LOG_TAG, ...) do {\
        ((void)elog_warn(LOG_TAG, __VA_ARGS__));    \
    }while(0)
#else
#define LOGW(LOG_TAG, fmt, arg...) (printf( __VA_ARGS__))// LY_INFO("[%s]"fmt,LOG_TAG, ##arg)
#endif
#endif

#ifndef LOGE
#ifdef DEBUG
#define LOGE(LOG_TAG, ...) do {\
        ((void)elog_error(LOG_TAG, __VA_ARGS__));   \
    }while(0)
#else
#define LOGE(LOG_TAG, fmt, arg...)  printf( __VA_ARGS__))// LY_INFO("[%s]"fmt,LOG_TAG, ##arg)
#endif
#endif

#ifndef LOGRW
#define LOGRW(...) do {\
		((void)elog_rw(__VA_ARGS__));	\
		LY_INFO(__VA_ARGS__);	\
	}while(0)
#endif

#define MAIN_WORK_DIR    "/usrdata"
#define CONFIGUER_FILE_PATH MAIN_WORK_DIR
#define MCU_SWUPGRADE_FILE_PATH          MAIN_WORK_DIR"/upgrade"



#define RED                  "\e[0;31m"
#define LOG_NONE                 "\e[0m"

#define ENABLE_ASSERT

#ifdef ENABLE_ASSERT
#define ASSERT(exp) do { \
                        if(!(exp)) { \
                            LOGD("Exit", RED "%s, %d occur serious problem!!!\n" LOG_NONE, __func__, __LINE__); \
                            exit(1); \
                        } \
                    }while(0)
#else
#define ASSERT(exp)
#endif




#ifndef FPRINTF
#define FPRINTF(DEVICE, ...) do {        \
        fprintf(DEVICE, __VA_ARGS__);    \
    }while(0)
#endif//        fprintf_output(__VA_ARGS__);     





extern void printRawData(uint8_t level, const char *tag,const char *head, UCHAR   const * data, int len);




#ifdef __cplusplus
}
#endif

#endif /* __ELOG_H__ */


